home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / cvs-1.8 / cvs-1 / cvs-1.8.1 / src / ignore.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  8.8 KB  |  406 lines

  1. /*
  2.  * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com>
  3.  */
  4.  
  5. #include "cvs.h"
  6.  
  7. /*
  8.  * Ignore file section.
  9.  * 
  10.  *    "!" may be included any time to reset the list (i.e. ignore nothing);
  11.  *    "*" may be specified to ignore everything.  It stays as the first
  12.  *        element forever, unless a "!" clears it out.
  13.  */
  14.  
  15. static char **ign_list;            /* List of files to ignore in update
  16.                      * and import */
  17. static char **s_ign_list = NULL;
  18. static int ign_count;            /* Number of active entries */
  19. static int s_ign_count = 0;
  20. static int ign_size;            /* This many slots available (plus
  21.                      * one for a NULL) */
  22. static int ign_hold;            /* Index where first "temporary" item
  23.                      * is held */
  24.  
  25. const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\
  26.  .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\
  27.  *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
  28.  
  29. #define IGN_GROW 16            /* grow the list by 16 elements at a
  30.                      * time */
  31.  
  32. /* Nonzero if we have encountered an -I ! directive, which means one should
  33.    no longer ask the server about what is in CVSROOTADM_IGNORE.  */
  34. int ign_inhibit_server;
  35.  
  36. /*
  37.  * To the "ignore list", add the hard-coded default ignored wildcards above,
  38.  * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
  39.  * ~/.cvsignore and the wildcards found in the CVSIGNORE environment
  40.  * variable.
  41.  */
  42. void
  43. ign_setup ()
  44. {
  45.     struct passwd *pw;
  46.     char file[PATH_MAX];
  47.     char *tmp;
  48.  
  49.     ign_inhibit_server = 0;
  50.  
  51.     /* Start with default list and special case */
  52.     tmp = xstrdup (ign_default);
  53.     ign_add (tmp, 0);
  54.     free (tmp);
  55.  
  56. #ifdef CLIENT_SUPPORT
  57.     /* The client handles another way, by (after it does its own ignore file
  58.        processing, and only if !ign_inhibit_server), letting the server
  59.        know about the files and letting it decide whether to ignore
  60.        them based on CVSROOOTADM_IGNORE.  */
  61.     if (!client_active)
  62. #endif
  63.     {
  64.     /* Then add entries found in repository, if it exists */
  65.     (void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM,
  66.             CVSROOTADM_IGNORE);
  67.     ign_add_file (file, 0);
  68.     }
  69.  
  70.     /* Then add entries found in home dir, (if user has one) and file exists */
  71.     if ((pw = (struct passwd *) getpwuid (getuid ())) && pw->pw_dir)
  72.     {
  73.     (void) sprintf (file, "%s/%s", pw->pw_dir, CVSDOTIGNORE);
  74.     ign_add_file (file, 0);
  75.     }
  76.  
  77.     /* Then add entries found in CVSIGNORE environment variable. */
  78.     ign_add (getenv (IGNORE_ENV), 0);
  79.  
  80.     /* Later, add ignore entries found in -I arguments */
  81. }
  82.  
  83. /*
  84.  * Open a file and read lines, feeding each line to a line parser. Arrange
  85.  * for keeping a temporary list of wildcards at the end, if the "hold"
  86.  * argument is set.
  87.  */
  88. void
  89. ign_add_file (file, hold)
  90.     char *file;
  91.     int hold;
  92. {
  93.     FILE *fp;
  94.     char line[1024];
  95.  
  96.     /* restore the saved list (if any) */
  97.     if (s_ign_list != NULL)
  98.     {
  99.     int i;
  100.  
  101.     for (i = 0; i < s_ign_count; i++)
  102.         ign_list[i] = s_ign_list[i];
  103.     ign_count = s_ign_count;
  104.     ign_list[ign_count] = NULL;
  105.  
  106.     s_ign_count = 0;
  107.     free (s_ign_list);
  108.     s_ign_list = NULL;
  109.     }
  110.  
  111.     /* is this a temporary ignore file? */
  112.     if (hold)
  113.     {
  114.     /* re-set if we had already done a temporary file */
  115.     if (ign_hold)
  116.     {
  117.         int i;
  118.  
  119.         for (i = ign_hold; i < ign_count; i++)
  120.         free (ign_list[i]);
  121.         ign_count = ign_hold;
  122.         ign_list[ign_count] = NULL;
  123.     }
  124.     else
  125.     {
  126.         ign_hold = ign_count;
  127.     }
  128.     }
  129.  
  130.     /* load the file */
  131.     fp = fopen (file, "r");
  132.     if (fp == NULL)
  133.     {
  134.     if (! existence_error (errno))
  135.         error (0, errno, "cannot open %s", file);
  136.     return;
  137.     }
  138.     while (fgets (line, sizeof (line), fp))
  139.     ign_add (line, hold);
  140.     if (fclose (fp) < 0)
  141.     error (0, errno, "cannot close %s", file);
  142. }
  143.  
  144. /* Parse a line of space-separated wildcards and add them to the list. */
  145. void
  146. ign_add (ign, hold)
  147.     char *ign;
  148.     int hold;
  149. {
  150.     if (!ign || !*ign)
  151.     return;
  152.  
  153.     for (; *ign; ign++)
  154.     {
  155.     char *mark;
  156.     char save;
  157.  
  158.     /* ignore whitespace before the token */
  159.     if (isspace (*ign))
  160.         continue;
  161.  
  162.     /*
  163.      * if we find a single character !, we must re-set the ignore list
  164.      * (saving it if necessary).  We also catch * as a special case in a
  165.      * global ignore file as an optimization
  166.      */
  167.     if ((!*(ign+1) || isspace (*(ign+1))) && (*ign == '!' || *ign == '*'))
  168.     {
  169.         if (!hold)
  170.         {
  171.         /* permanently reset the ignore list */
  172.         int i;
  173.  
  174.         for (i = 0; i < ign_count; i++)
  175.             free (ign_list[i]);
  176.         ign_count = 0;
  177.         ign_list[0] = NULL;
  178.  
  179.         /* if we are doing a '!', continue; otherwise add the '*' */
  180.         if (*ign == '!')
  181.         {
  182.             ign_inhibit_server = 1;
  183.             continue;
  184.         }
  185.         }
  186.         else if (*ign == '!')
  187.         {
  188.         /* temporarily reset the ignore list */
  189.         int i;
  190.  
  191.         if (ign_hold)
  192.         {
  193.             for (i = ign_hold; i < ign_count; i++)
  194.             free (ign_list[i]);
  195.             ign_hold = 0;
  196.         }
  197.         s_ign_list = (char **) xmalloc (ign_count * sizeof (char *));
  198.         for (i = 0; i < ign_count; i++)
  199.             s_ign_list[i] = ign_list[i];
  200.         s_ign_count = ign_count;
  201.         ign_count = 0;
  202.         ign_list[0] = NULL;
  203.         continue;
  204.         }
  205.     }
  206.  
  207.     /* If we have used up all the space, add some more */
  208.     if (ign_count >= ign_size)
  209.     {
  210.         ign_size += IGN_GROW;
  211.         ign_list = (char **) xrealloc ((char *) ign_list,
  212.                        (ign_size + 1) * sizeof (char *));
  213.     }
  214.  
  215.     /* find the end of this token */
  216.     for (mark = ign; *mark && !isspace (*mark); mark++)
  217.          /* do nothing */ ;
  218.  
  219.     save = *mark;
  220.     *mark = '\0';
  221.  
  222.     ign_list[ign_count++] = xstrdup (ign);
  223.     ign_list[ign_count] = NULL;
  224.  
  225.     *mark = save;
  226.     if (save)
  227.         ign = mark;
  228.     else
  229.         ign = mark - 1;
  230.     }
  231. }
  232.  
  233. /* Set to 1 if ignore file patterns should be matched in a case-insensitive
  234.    fashion.  */
  235. int ign_case;
  236.  
  237. /* Return 1 if the given filename should be ignored by update or import. */
  238. int
  239. ign_name (name)
  240.     char *name;
  241. {
  242.     char **cpp = ign_list;
  243.  
  244.     if (cpp == NULL)
  245.     return (0);
  246.  
  247.     if (ign_case)
  248.     {
  249.     /* We do a case-insensitive match by calling fnmatch on copies of
  250.        the pattern and the name which have been converted to
  251.        lowercase.  */
  252.     char *name_lower;
  253.     char *pat_lower;
  254.     char *p;
  255.  
  256.     name_lower = xstrdup (name);
  257.     for (p = name_lower; *p != '\0'; ++p)
  258.         *p = tolower (*p);
  259.     while (*cpp)
  260.     {
  261.         pat_lower = xstrdup (*cpp++);
  262.         for (p = pat_lower; *p != '\0'; ++p)
  263.         *p = tolower (*p);
  264.         if (fnmatch (pat_lower, name_lower, 0) == 0)
  265.         goto matched;
  266.         free (pat_lower);
  267.     }
  268.     free (name_lower);
  269.     return 0;
  270.       matched:
  271.     free (name_lower);
  272.     free (pat_lower);
  273.     return 1;
  274.     }
  275.     else
  276.     {
  277.     while (*cpp)
  278.         if (fnmatch (*cpp++, name, 0) == 0)
  279.         return 1;
  280.     return 0;
  281.     }
  282. }
  283.  
  284. /* FIXME: This list of dirs to ignore stuff seems not to be used.  */
  285.  
  286. static char **dir_ign_list = NULL;
  287. static int dir_ign_max = 0;
  288. static int dir_ign_current = 0;
  289.  
  290. /* add a directory to list of dirs to ignore */
  291. void ign_dir_add (name)
  292.      char *name;
  293. {
  294.   /* make sure we've got the space for the entry */
  295.   if (dir_ign_current <= dir_ign_max)
  296.     {
  297.       dir_ign_max += IGN_GROW;
  298.       dir_ign_list = (char **) xrealloc ((char *) dir_ign_list, (dir_ign_max+1) * sizeof(char*));
  299.     }
  300.  
  301.   dir_ign_list[dir_ign_current] = name;
  302.  
  303.   dir_ign_current += 1 ;
  304. }
  305.  
  306.  
  307. /* this function returns 1 (true) if the given directory name is part of
  308.  * the list of directories to ignore
  309.  */
  310.  
  311. int ignore_directory (name)
  312.      char *name;
  313. {
  314.   int i;
  315.  
  316.   if (!dir_ign_list)
  317.     return 0;
  318.  
  319.   i = dir_ign_current;
  320.   while (i--)
  321.     {
  322.       if (strncmp(name, dir_ign_list[i], strlen(dir_ign_list[i])) == 0)
  323.     return 1;
  324.     }
  325.  
  326.   return 0;
  327. }
  328.  
  329. /*
  330.  * Process the current directory, looking for files not in ILIST and not on
  331.  * the global ignore list for this directory.  If we find one, call PROC
  332.  * passing it the name of the file and the update dir.
  333.  */
  334. void
  335. ignore_files (ilist, update_dir, proc)
  336.     List *ilist;
  337.     char *update_dir;
  338.     Ignore_proc proc;
  339. {
  340.     DIR *dirp;
  341.     struct dirent *dp;
  342.     struct stat sb;
  343.     char *file;
  344.     char *xdir;
  345.  
  346.     /* we get called with update_dir set to "." sometimes... strip it */
  347.     if (strcmp (update_dir, ".") == 0)
  348.     xdir = "";
  349.     else
  350.     xdir = update_dir;
  351.  
  352.     dirp = opendir (".");
  353.     if (dirp == NULL)
  354.     return;
  355.  
  356.     ign_add_file (CVSDOTIGNORE, 1);
  357.     wrap_add_file (CVSDOTWRAPPER, 1);
  358.  
  359.     while ((dp = readdir (dirp)) != NULL)
  360.     {
  361.     file = dp->d_name;
  362.     if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0)
  363.         continue;
  364.     if (findnode_fn (ilist, file) != NULL)
  365.         continue;
  366.  
  367.     if (
  368. #ifdef DT_DIR
  369.         dp->d_type != DT_UNKNOWN ||
  370. #endif
  371.         lstat(file, &sb) != -1) 
  372.     {
  373.  
  374.         if (
  375. #ifdef DT_DIR
  376.         dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN &&
  377. #endif
  378.         S_ISDIR(sb.st_mode))
  379.         {
  380.         char temp[PATH_MAX];
  381.  
  382.         (void) sprintf (temp, "%s/%s", file, CVSADM);
  383.         if (isdir (temp))
  384.             continue;
  385.         }
  386. #ifdef S_ISLNK
  387.         else if (
  388. #ifdef DT_DIR
  389.         dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN && 
  390. #endif
  391.         S_ISLNK(sb.st_mode))
  392.         {
  393.         continue;
  394.         }
  395. #endif
  396.         }
  397.  
  398.     /* We could be ignoring FIFOs and other files which are neither
  399.        regular files nor directories here.  */
  400.     if (ign_name (file))
  401.         continue;
  402.     (*proc) (file, xdir);
  403.     }
  404.     (void) closedir (dirp);
  405. }
  406.